#include "serial_protocol.h"

SerialProrocol::SerialProrocol(uint32_t bufSize):ProrocolBase(bufSize)
{

}

SerialProrocol::~SerialProrocol()
{

}

const uint8_t* SerialProrocol::packageBuffer(const uint8_t* buf, uint32_t inlen, int32_t& outlen)
{
	outlen = inlen;
	return buf;
}

int SerialProrocol::pushByte(uint8_t point)
{
	uint32_t offset = getRecvOffset();  
    uint8_t* buf = getRxbuf();
    uint32_t bufSize = getBuffSize();
	

	if(offset > bufSize){
		setRecvOffset(0);
	}

	static uint8_t step = 0;
	static uint8_t len = 0;
	static uint8_t data_len = 0;
	static uint16_t crc16;

	switch(step)
	{
	    case 0://接收帧头1状态
	        if(point == 0xA5)
	        {
				offset = 0;
	            step++;
	            buf[offset++] = point;
	        }break;
	    case 1://接收帧头2状态
	        if(point== 0x5A)
	        {
	            step++;
	            buf[offset++] = point;
	        }
	        else if(point == 0xA5)
	        {
	            step = 1;
	        }
	        else
	        {
	            step = 0;
	        }
	        break;
	    case 2://接收数据长度字节状态
	        step++;
	        buf[offset++] = point;
	        len = point;
	        break;
	    case 3://接收命令字节状态
	        step++;
	        buf[offset++] = point;
	        if(len == 0)step++;//数据字节长度为0则跳过数据接收状态
	        break;
	    case 4://接收len字节数据状态
	        buf[offset++] = point;
			data_len++;
	        if(data_len == len)//利用指针地址偏移判断是否接收完len位数据
	        {
	            step++;
	        }
	        break;
	    case 5://接收crc16校验高8位字节
	        step++;
	        crc16 = point;
	        break;
	    case 6://接收crc16校验低8位字节
	        crc16 <<= 8;
	        crc16 += point;
	        if(crc16 == CRC16_Check(buf,offset))//校验正确进入下一状态
	        {
				buf[offset++] = point;
	            step ++;
	        }
	        else if(point == 0xA5)
	        {
				offset = 0;
				buf[offset++] = point;
	            step = 1;
	        }
	        else
	        {
	            step = 0;
	        }
	        break;
	    case 7://接收帧尾
	        if(point == 0xFF)//帧尾接收正确
	        {
	            step = 0;
				buf[offset++] = point;
				setRecvOffset(offset);
				return 1;
	        }
	        else if(point == 0xA5)
	        {
				offset = 0;
				buf[offset++] = point;
	            step = 1;
	        }
	        else
	        {
	            step = 0;
	        }
	        break;
	    default:step=0;break;//多余状态，正常情况下不可能出现
	}
	setRecvOffset(offset);
	return 0;
}

uint16_t SerialProrocol::CRC16_Check(const uint8_t *data,uint8_t len)
{
    uint16_t CRC16 = 0xFFFF;
    uint8_t state,i,j;
    for(i = 0; i < len; i++ )
    {
        CRC16 ^= data[i];
        for( j = 0; j < 8; j++)
        {
            state = CRC16 & 0x01;
            CRC16 >>= 1;
            if(state)
            {
                CRC16 ^= 0xA001;
            }
        }
    }
    return CRC16;
}
